#include "sh_lib.h"
#include "main.h"
#include "digital_tube.h"
#include "lift_info.h"

struct digital_tube_data {
    char symbol;
    uint8_t value;
};

static struct digital_tube_data digital_tube_map[] = {
    {'0', 0x3f},
    {'1', 0x06},
    {'2', 0x5b},
    {'3', 0x4f},
    {'4', 0x66},
    {'5', 0x6d},
    {'6', 0x7d},
    {'7', 0x07},
    {'8', 0x7f},
    {'9', 0x6f},
    {'F', 0x71},
    {'-', 0x40},
    {' ', 0x00},
    {'.', 0xBF},
};

static void board_digital_tube_show_value(uint8_t value)
{
    GPIO_PinState state[8] = {0};

    for (int i = 0; i < 8; i++) {
        state[i] = (value & (1 << i)) ? GPIO_PIN_RESET : GPIO_PIN_SET;
    }

    HAL_GPIO_WritePin(A_GPIO_Port, A_Pin, state[0]);
    HAL_GPIO_WritePin(B_GPIO_Port, B_Pin, state[1]);
    HAL_GPIO_WritePin(C_GPIO_Port, C_Pin, state[2]);
    HAL_GPIO_WritePin(D_GPIO_Port, D_Pin, state[3]);
    HAL_GPIO_WritePin(E_GPIO_Port, E_Pin, state[4]);
    HAL_GPIO_WritePin(F_GPIO_Port, F_Pin, state[5]);
    HAL_GPIO_WritePin(G_GPIO_Port, G_Pin, state[6]);
    HAL_GPIO_WritePin(H_GPIO_Port, H_Pin, state[7]);
}

static void board_digital_tube_select_none(void)
{
    HAL_GPIO_WritePin(GRID1_GPIO_Port, GRID1_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GRID2_GPIO_Port, GRID2_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GRID3_GPIO_Port, GRID3_Pin, GPIO_PIN_RESET);
}

static int board_digital_tube_select(uint8_t index)
{
    switch (index) {
    case 0:
        HAL_GPIO_WritePin(GRID3_GPIO_Port, GRID3_Pin, GPIO_PIN_SET);
        return 0;
    
    case 1:
        HAL_GPIO_WritePin(GRID2_GPIO_Port, GRID2_Pin, GPIO_PIN_SET);
        return 0;
    
    case 2:
        HAL_GPIO_WritePin(GRID1_GPIO_Port, GRID1_Pin, GPIO_PIN_SET);
        return 0;
    
    default:
        return -1;
    }
}

static int board_digital_tube_show_symbol(char symbol)
{
    for (int i = 0; i < ARRAY_SIZE(digital_tube_map); i++) {
        if (symbol == digital_tube_map[i].symbol) {
            board_digital_tube_show_value(digital_tube_map[i].value);
            return 0;
        }
    }

    board_digital_tube_show_value(0x00);
    return -1;
}

void board_digital_tube_show_number(uint16_t value, uint8_t places)
{
    static uint8_t index = 0;
    uint8_t symbol = ' ';

    board_digital_tube_select_none();

    switch (index) {
    case 0:
        symbol = '0' + value % 10;
        break;

    case 1:
        symbol = '0' + value / 10 % 10;
        break;

    case 2:
        if (places <= 2) {
            symbol = ' ';
        } else {
            symbol = '0' + value / 100 % 10;
        }
        break;
    }

    board_digital_tube_select(index);
    board_digital_tube_show_symbol(symbol);
    
    index = (index + 1) % 3;
}

void board_digital_tube_show_speed(uint16_t value)
{
    static uint8_t index = 0;
    uint8_t symbol = ' ';

    board_digital_tube_select_none();

    switch (index) {
    case 0:
        symbol = '0' + value % 10;
        break;

    case 1:
        symbol = '0' + value / 10 % 10;
        break;

    case 2:
        symbol = '.';
        break;
    }

    board_digital_tube_select(index);
    board_digital_tube_show_symbol(symbol);
    
    index = (index + 1) % 3;
}

void board_digital_tube_show_menu(uint8_t menu_index)
{
    static uint8_t index = 0;
    uint8_t symbol = ' ';

    board_digital_tube_select_none();

    switch (index) {
    case 0:
        symbol = '0' + menu_index % 10;
        break;

    case 1:
        symbol = '0' + menu_index / 10;
        break;

    case 2:
        symbol = 'F';
        break;
    }

    board_digital_tube_select(index);
    board_digital_tube_show_symbol(symbol);
    
    index = (index + 1) % 3;
}

void board_digital_tube_show_runnig(void)
{
    static uint8_t index = 0;

    board_digital_tube_select_none();
    board_digital_tube_select(index);
    board_digital_tube_show_symbol('-');

    index = (index + 1) % 3;
}

void board_digital_tube_clear(void)
{
    static uint8_t index = 0;

    board_digital_tube_select_none();
    board_digital_tube_select(index);
    board_digital_tube_show_symbol(' ');

    index = (index + 1) % 3;
}

static struct digital_tube_ctrl digital_tube_ctrl = {0};

void digital_tube_display_timer_cb(void *param)
{
    uint32_t position = 0;

    switch (digital_tube_ctrl.type) {
    case DIGITAL_TUBE_MENU:
        board_digital_tube_show_menu(digital_tube_ctrl.menu_item);
        break;

    case DIGITAL_TUBE_NUMBER:
        lift_info_get_position(&position);
        if (digital_tube_ctrl.menu_item == 10) {
            digital_tube_ctrl.value = position / 1000;
        } else if (digital_tube_ctrl.menu_item == 11) {
            digital_tube_ctrl.value = position % 1000;
        }
        board_digital_tube_show_number(digital_tube_ctrl.value, 3);
        break;

    case DIGITAL_TUBE_RUNNING:
        if (lift.is_floor_info_learned) {
            board_digital_tube_show_number(lift.current_floor + 1, 2);
        } else {
            board_digital_tube_show_runnig();
        }
        break;
    
    case DIGITAL_TUBE_SPEED:
        board_digital_tube_show_speed(digital_tube_ctrl.value);
        break;

    case DIGITAL_TUBE_CLEAR:
        board_digital_tube_clear();
        break;

    default:
        break;
    }
}

void digital_tube_set_value(enum digital_tube_display_type_e type, uint16_t value)
{
    digital_tube_ctrl.type = type;
    if (type == DIGITAL_TUBE_MENU) {
        digital_tube_ctrl.menu_item = value;
    } else {
        digital_tube_ctrl.value = value;
    }

    if (type == DIGITAL_TUBE_RUNNING) {
        digital_tube_ctrl.menu_item = 0;
    }
}

uint16_t digital_tube_get_num_value(void)
{
    return digital_tube_ctrl.value;
}

void digital_tube_set_type(enum digital_tube_display_type_e type)
{
    digital_tube_ctrl.type = type;
}

uint16_t digital_tube_menu_get_index(void)
{
    return digital_tube_ctrl.menu_item;
}

uint16_t digital_tube_menu_adjust_value(int8_t adjust)
{
    if (adjust == 0) {
        return digital_tube_ctrl.menu_item;
    } else if (adjust > 0) {
        if (digital_tube_ctrl.menu_item < 11) {
            digital_tube_ctrl.menu_item++;
        }
    } else if (adjust < 0) {
        if (digital_tube_ctrl.menu_item > 0) {
            digital_tube_ctrl.menu_item--;
        }
    }

    return digital_tube_ctrl.menu_item;
}




